//创建实例的时候，我们经常需要同时初始化这个实例的字段
Person ming = new Person();
ming.setName("小明");
ming.setAge(12);

//初始化对象实例需要3行代码，而且，如果忘了调用setName()或者setAge()，这个实例内部的状态就是不正确的。

//这时，我们就需要构造方法。

//构造方法
class Person {
	private String name;
	private int age;

	//构造方法,的名称就是类名
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return this.name;
	}

	public int getAge() {
		return this.age;
	}
}

public class Main {
	public static void main(String[] args) {
		Person p = new Person("Xiao Ming",15);

		System.out.println(p.getName());
		System.out.println(p.getAge());
	}
}
//和普通方法相比，构造方法没有返回值（也没有void），调用构造方法，必须用new操作符。



// 默认构造方法
//是不是任何class都有构造方法？ 是的。
//如果一个类没有定义构造方法，编译器会自动为我们生成一个默认构造方法，它没有参数，也没有执行语句

//！！！如果我们自定义了一个构造方法，那么，编译器就不再自动创建默认构造方法



//如果既要能使用带参数的构造方法，又想保留不带参数的构造方法，那么只能把两个构造方法都定义出来
public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Xiao Ming", 15); // 既可以调用带参数的构造方法
        Person p2 = new Person(); // 也可以调用无参数构造方法
    }
}

class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }
}

//没有在‘构造方法’中初始化字段时，引用类型的字段默认是null，数值类型的字段用默认值，int类型默认值是0，布尔类型默认值是false
class Person {
    private String name; // 默认初始化为null
    private int age; // 默认初始化为0

    public Person() {
    }
}

//也可以对字段直接进行初始化：
class Person {
    private String name = "Unamed";
    private int age = 10;
}


//那么问题来了：既对字段进行初始化，又在构造方法中对字段进行初始化：
class Person {
    private String name = "Unamed";
    private int age = 10;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

/*
在Java中，创建对象实例的时候，按照如下顺序进行初始化：

先初始化field字段，例如，int age = 10;表示字段初始化为10，double salary;表示字段默认初始化为0，String name;表示引用类型字段默认初始化为null；

执行构造方法的代码进行初始化。

因此，构造方法的代码由于后运行，所以，new Person("Xiao Ming", 12)的字段值最终由构造方法的代码确定。
*/



//多构造方法
class Person {
    private String name;
    private int age;

    //构造1
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //构造2
    public Person(String name) {
        this.name = name;
        this.age = 12;
    }

    //构造3
    public Person() {
    }
}
/*
如果调用new Person("Xiao Ming", 20);，会自动匹配到构造方法public Person(String, int)。

如果调用new Person("Xiao Ming");，会自动匹配到构造方法public Person(String)。

如果调用new Person();，会自动匹配到构造方法public Person()。
*/


// --------- 重点 ---------- this()
//个构造方法可以调用其他构造方法，这样做的目的是便于代码复用。调用其他构造方法的语法是this(…)：
class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name) {
        this(name, 18); // 调用另一个构造方法Person(String, int)
    }

    public Person() {
        this("Unnamed"); // 调用另一个构造方法Person(String)
    }
}



//练习
//请给Person类增加(String, int)的构造方法：
class Person {
    private String name;
    private int age;

    public Person(String name,int age) {
    	this.name = name;
    	this.age = age;
    }

    public Person(String name) {
    	this(name,18);
    } 

    public Person() {
    	this.name = "Unnamed";
    	this.age = 18;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class Main {
    public static void main(String[] args) {
        // TODO: 给Person增加构造方法:
        Person ming = new Person("小明", 12);
        
        System.out.println(ming.getName());
        System.out.println(ming.getAge());
    }
}

/*
小结
	1.实例在创建时通过new操作符会调用其对应的构造方法，构造方法用于初始化实例；

	2.没有定义构造方法时，编译器会自动创建一个默认的无参数构造方法；

	3.可以定义多个构造方法，编译器根据参数自动判断；

	4.可以在一个构造方法内部调用另一个构造方法，便于代码复用。

*/








